<template>
  <view class="app-container" style="overflow: hidden;">
    <image class="background" src="/static/images/background.png" mode="aspectFill"></image>

    <view class="bar-box" :style="{ marginTop: titleMargin + 'px', position: 'fixed' }">
      <image class="back" src="/static/images/back.png" @click="back"></image>
      <view class="title">{{ username }}</view>
    </view>

    <scroll-view scroll-y enable-flex class="chat-box" :scroll-top="scrollTop" :scroll-with-animation="true" @scrolltoupper="loadMore">
      <block v-for="(item, index) in list" :key="index">
        <block v-if="item.msg_type == 1">
          <view class="row friend-row" v-if="item.user_id == to_user_id">
            <image class="avatar" @click="goUserDetail(item.user_id)" :src="avatar" mode="aspectFill"></image>
            <view class="msg">{{ item.content }}</view>
          </view>
          <view class="row me-row" v-else>
            <view class="msg">{{ item.content }}</view>
            <image class="avatar" :src="login_avatar" mode="aspectFill"></image>
          </view>
        </block>
        <block v-if="item.msg_type == 2">
          <view class="row friend-row" v-if="item.user_id == to_user_id">
            <image class="avatar" :src="avatar" mode="aspectFill"></image>
            <view class="msg" @click="playVoiceFromServer(item.url)">
              <image src="/static/images/friend_voice.png" class="voice"></image>
              <view class="duration">{{ item.duration }}</view>
            </view>
          </view>
          <view class="row me-row" v-else>
            <view class="msg" @click="playVoiceFromServer(item.url)">
              <view class="duration">{{ item.duration }}</view>
              <image src="/static/images/me_voice.png" class="voice"></image>
            </view>
            <image class="avatar" :src="login_avatar" mode="aspectFill"></image>
          </view>
        </block>
      </block>
    </scroll-view>

    <view class="send-box">
      <block v-if="send_type == 1">
        <image class="yy" src="/static/images/yy_btn.png" @click="changeSendType(2)"></image>
        <input class="input" type="text" :value="content" @input="changeContent" @confirm="sendMsg"/>
        <view class="btn send-btn" @click="sendMsg">发送</view>
      </block>
      <block v-else>
        <image class="yy" src="/static/images/jp.png" @click="changeSendType(1)"></image>
        <view class="btn-box">
          <block v-if="recorder_status != 1">
            <view class="btn start-btn" @click="startRecorder">点击 说话</view>
          </block>
          <block v-else-if="recorder_status == 1">
            <view class="btn cancel-btn" @click="cancelRecorder">取消</view>
            <view class="btn send-btn" @click="sendRecorder">发送</view>
          </block>
        </view>
      </block>
    </view>
  </view>
</template>

<script>
import http from '@/utils/http'
import {sendTextMessage, onMessage, offMessage} from '@/utils/function/ws.js';

var recorderManager = uni.getRecorderManager();
var innerAudioContext = uni.createInnerAudioContext();

export default {
  data() {
    return {
      to_user_id: 0,
      username: '',
      avatar: '',
      login_avatar: '',
      title: '',
      titleMargin: 0, // 动态顶部间距
      send_type: 1, // 1：发送文字，2：发送语音
      recorder_status: 0,// 0：未录音，1：正在录音，2：取消录音，3：结束录音
      list: [],
      page: 1,
      pagesize: 20,
      content: '',
      scrollTop: 0,
      sensitive_words: [],
      is_playing: false,// 是否正在播放语音
    };
  },

  created() {
    this.setDynamicMargin(); // 设置动态间距
  },

  onShow: function (){
    uni.hideShareMenu();
  },

  onLoad: function (options) {
    var {to_user_id, username, avatar, index} = options;// 聊天对象信息

    this.to_user_id = to_user_id;
    this.username = username;
    this.avatar = avatar;

    var pages = getCurrentPages();
    // 上一个页面
    var prevPage = pages[pages.length - 2];
    if (prevPage.route == 'pages/chat_list/chat_list') {
      // 修改上一个页面的数据
      prevPage.$vm.list[index].unread_num = 0;
    }
    this.login_avatar = uni.getStorageSync('avatar');// 当前登录人头像

    this.chatList();

    this.$http.post('/index/Chat/getChatSensitive').then(res => {
      this.sensitive_words = res.data.data
    })

    // 订阅 WebSocket 消息
    this.messageHandler = (data) => {
      console.log(data)
      if (data.type === 'receive') {
        console.log('收到消息', data)
        this.list.push(data);

        this.scrollTop = this.$common.getRandomInt();

        this.$http.post('/index/Chat/read', {user_id: data.to_user_id, to_user_id: data.user_id})
      }
    };
    onMessage(this.messageHandler);

    recorderManager.onError(function (err) {
      console.error('录音错误:', err);
    });

    recorderManager.onStop(e => {
      if (this.recorder_status == 3) {
        var user_id = uni.getStorageSync('user_id'), to_user_id = this.to_user_id;
        // 发送语音
        var {duration, fileSize, tempFilePath} = e;

        if (duration < 1000) {
          uni.showToast({
            title: '说话时间太短',
            icon: 'none'
          })
          return false;
        }

        this.uploadVoice(tempFilePath, http.config.baseURL + '/index/Chat/uploadVoice', {})
          .then(url => {
            var data = {user_id, to_user_id, url, duration, fileSize};
            this.$http.post('/index/Chat/sendVoice', data).then(res => {
              if (res.data.result == 1) {
                this.scrollTop = this.$common.getRandomInt();

                var duration_str = parseInt(duration / 1000) + 's';
                this.list.push({user_id, to_user_id, content: '[语音消息]', msg_type: 2, duration: duration_str, url});

                sendTextMessage("send", user_id, to_user_id, '[语音消息]', 2, duration_str, url);
              } else {
                uni.showToast({
                  title: res.msg,
                  icon: 'none'
                })
              }
            })
          })
          .catch(error => {
            console.error('上传失败:', error);
          });
      }
    })
  },

  onUnload() {
    // 取消监听
    offMessage(this.messageHandler);
  },

  methods: {
    back: function () {
      uni.navigateBack();
    },

    goUserDetail: function (to_user_id) {
      uni.navigateTo({
        url: '/pages/user_details/user_details?user_id=' + to_user_id
      })
    },

    setDynamicMargin() {
      const windowInfo = uni.getWindowInfo();
      this.titleMargin = windowInfo.statusBarHeight + 10; // 直接使用状态栏高度
    },

    changeContent: function (e) {
      this.content = e.detail.value;
    },

    changeSendType: function (send_type) {
      this.send_type = send_type;
    },

    uploadVoice(filePath, serverUrl, formData = {}) {
      return new Promise((resolve, reject) => {
        if (!filePath) {
          uni.showToast({
            title: '没有可上传的录音文件',
            icon: 'none'
          });
          return reject('录音文件路径为空');
        }

        uni.uploadFile({
          url: serverUrl, // 服务器上传地址
          filePath: filePath, // 录音文件路径
          name: 'file', // 后端接收字段名
          formData: formData, // 额外参数
          header: {
            'Content-Type': 'multipart/form-data'
          },
          success: (res) => {
            try {
              let data = JSON.parse(res.data);
              if (data.status === 'success') {
                resolve(data.url); // 返回文件 URL
              } else {
                uni.showToast({
                  title: data.message || '上传失败',
                  icon: 'none'
                });
                reject(data.message || '上传失败');
              }
            } catch (error) {
              reject('服务器返回格式错误');
            }
          },
          fail: (err) => {
            console.log('上传失败', err);
            uni.showToast({
              title: '上传失败',
              icon: 'none'
            });
            reject(err);
          }
        });
      });
    },

    sendMsg: function (e) {
      var content = e.detail.value || this.content,
        to_user_id = this.to_user_id,
        user_id = uni.getStorageSync('user_id'),
        sensitive_words = this.sensitive_words;

      if (sensitive_words.some(word => content.includes(word))) {
        uni.showToast({
          title: '含有敏感词，请重新输入',
          icon: 'none'
        })
        return false;
      }

      this.content = '';
      this.list.push({user_id, to_user_id, content, msg_type: 1});

      // 发送长连接消息
      this.send(user_id, to_user_id, content);
    },

    // 开始录音
    startRecorder() {
      this.recorder_status = 1;

      innerAudioContext.stop(); // 停止播放语音
      this.is_playing = false;

      uni.showLoading({
        title: '正在录音中...'
      })

      recorderManager.start({
        duration: 60000, // 60 秒
        format: 'aac', // 高效编码
        sampleRate: 44100, // 高采样率
        encodeBitRate: 192000 // 192 kbps，高质量
      });
    },

    // 取消录音
    cancelRecorder() {
      uni.hideLoading();
      this.recorder_status = 2;
      recorderManager.stop();
    },

    // 发送录音
    sendRecorder() {
      uni.hideLoading();
      this.recorder_status = 3;
      recorderManager.stop();
    },

    playVoiceFromServer(url) {
      if (this.is_playing == false) {
        if (!url) {
          uni.showToast({
            title: '音频 URL 为空',
            icon: 'none'
          });
          return;
        }

        innerAudioContext.autoplay = true;
        innerAudioContext.src = http.config.baseURL + url; // 服务器上的音频 URL
        innerAudioContext.onPlay(() => {
          this.is_playing = true;
          console.log('开始播放服务器语音:', url);
        });
        innerAudioContext.onEnded(() => {
          this.is_playing = false;
        })
        innerAudioContext.onError((res) => {
          this.is_playing = false;
          console.log('播放失败', res.errMsg);
        });
      }
    },

    loadMore: function () {
      this.chatList(this.page + 1, false);
    },

    chatList: function (incPage = 0, ctrScrollTop = true) {
      var page = incPage ? incPage : this.page;

      this.$http.post('/index/Chat/chatList', {
        user_id: uni.getStorageSync('user_id'),
        to_user_id: this.to_user_id,
        page: page,
        pagesize: this.pagesize
      }).then((res) => {
        if (page == 1) {
          var list = res.data.data;
          list.reverse();
          this.list = list;
        } else {
          // 加载更多
          var list = this.list;

          for (var i = 0; i < list.length; i++) {
            list.unshift(res.data.data[i])
          }

          this.list = list;
          this.page = page;
        }

        if (ctrScrollTop) this.scrollTop = this.$common.getRandomInt();
      })
    },

    send: function (user_id, to_user_id, content, is_worker = true) {
      if (!to_user_id && !user_id) {
        uni.showToast({
          title: '发送失败',
          icon: 'none'
        })
        return false;
      }

      if (content == '') return false;

      var data = {user_id, to_user_id, content};

      this.$http.post('/index/Chat/send', data).then(res => {
        if (res.data.result == 1) {
          this.scrollTop = this.$common.getRandomInt();

          if (is_worker) sendTextMessage("send", user_id, to_user_id, content)
        } else {
          uni.showToast({
            title: '发送失败',
            icon: 'none'
          })
        }
      })
    },
  },
}
</script>

<style lang="scss">
.app-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0 10rpx;

  .chat-box {
    display: flex;
    flex-direction: column;
    position: fixed;
    height: 80vh;
    left: 20rpx;
    right: 20rpx;
    top: 180rpx;
    bottom: 160rpx;
    width: calc(100% - 40rpx);

    .row {
      margin-bottom: 20rpx;
    }

    .friend-row {
      display: flex;

      .avatar {
        width: 80rpx;
        height: 80rpx;
        border-radius: 20rpx;
        margin-right: 10rpx;
        flex-shrink: 0;
      }

      .msg {
        padding: 20rpx;
        border-radius: 20rpx;
        background: #fff;
        max-width: calc(100% - 260rpx);

        display: flex;
        align-items: center;

        .voice {
          width: 30rpx;
          height: 30rpx;
          margin-right: 10rpx;
          flex-shrink: 0;
        }

      }
    }

    .me-row {
      display: flex;
      justify-content: flex-end;

      .avatar {
        width: 80rpx;
        height: 80rpx;
        border-radius: 20rpx;
        margin-left: 10rpx;
        flex-shrink: 0;
      }

      .msg {
        padding: 20rpx;
        border-radius: 20rpx;
        background: #4cd964;
        max-width: calc(100% - 260rpx);

        display: flex;
        align-items: center;

        .voice {
          width: 40rpx;
          height: 40rpx;
          margin-left: 10rpx;
          flex-shrink: 0;
        }
      }
    }
  }

  .send-box {
    display: flex;
    align-items: center;
    background: #dddfe2;
    padding: 10rpx 20rpx;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;

    .yy {
      width: 50rpx;
      height: 50rpx;
      flex-shrink: 0;
    }

    .input {
      flex: 1;
      margin: 20rpx;
      padding: 10rpx 20rpx;
      background: #fff;
      border-radius: 10rpx;
      border: none;
    }

    .send-btn {
      background: #4cd964;
      color: #fff;
      padding: 12rpx 20rpx;
      border-radius: 10rpx;
    }


    .btn-box {
      display: flex;
      align-items: center;
      width: 100%;
      margin: 20rpx;

      .btn {
        background: #fff;
        border-radius: 10rpx;
        color: #000;
        border: none;
        padding: 12rpx 0;
        flex: 1;
        text-align: center;
        margin-right: 20rpx;

        &:last-child {
          margin-right: 0;
        }
      }

      .cancel-btn {
        background: #de4444;
        color: #fff;
      }

      .send-btn {
        background: #4cd964;
        color: #fff;
      }
    }
  }
}
</style>
